package com.beiding.jsonanalyzer.flow;

import java.util.*;

/**
 * 分支网关
 * 根据refer产生新的分支
 *
 * @author 丁常磊
 * @date 2022/5/12 12:21
 */

public class BranchGateway<T> {


    /**
     * 计算资源
     */
    private ComputeResource computeResource;

    /**
     * 父级节点
     */
    private Branch<T> parentBranch;

    /**
     * 前置引用链
     */
    private List<Object> frontReferLink;


    private ValueNodeFactory<T> valueNodeFactory;


    public BranchGateway(Branch<T> parentBranch, ComputeResource computeResource, List<Object> frontReferLink, ValueNodeFactory<T> valueNodeFactory) {
        this.parentBranch = parentBranch;
        this.computeResource = computeResource;
        this.frontReferLink = frontReferLink;
        this.valueNodeFactory = valueNodeFactory;
    }

    /**
     * 分支暂存
     */
    private volatile Map<Object, BranchNode<T>> branchMap = new HashMap<>();

    /**
     * 将内容提交至特定的分支上
     * 如果分支不存在就创建
     *
     * @param refer 分支引用
     */
    public BranchResult getOneBranch(Object referKey, Object refer) {

        BranchResult offerContentResult = new BranchResult();

        offerContentResult.newBranch = false;

        //获取分支
        offerContentResult.branch = branchMap.computeIfAbsent(refer, k -> {

            Object z = refer;
            if (z == null) {
                z = BranchNode.class;
            }

            //创建一个新的分支
            TaskSlot oneSlot = computeResource.getOneSlot(z.hashCode());
            offerContentResult.newBranch = true;

            Branch<T> branch = new Branch<>();

            branch.setValueNodeFactory(valueNodeFactory);

            //计算源
            branch.setComputeResource(computeResource);

            //计算任务槽
            branch.setTaskSlot(oneSlot);

            //引用链
            List<Object> referLink = new ArrayList<>(frontReferLink);
            referLink.add(refer);
            branch.setBranchReferLink(referLink);

            //本级引用

            BranchNode<T> branchNode = new BranchNode<>(branch);
//            nextLayer.addNode(branchNode);
            branch.setFirstNode(branchNode);

            //父级
            branch.setParent(parentBranch);
            branch.setReferKeyValue(referKey,refer);

            StringBuilder nameBuilder = new StringBuilder("[").append(branch.getReferKey()).append("=").append(refer).append("]");

            Branch po = branch.getParent();
            while (po != null) {
                nameBuilder.insert(0, "->").insert(0, "[" + po.getReferKey() + "=" + po.getRefer() + "]");
                po = po.getParent();
            }

            branch.setName(nameBuilder.toString());

            //在父节点中注册
            if (parentBranch != null) {
                parentBranch.addChild(branch);
            }

            //子节点
            branch.setChildren(new ArrayList<>());


            return branchNode;
        });
        return offerContentResult;
    }

    /**
     * 清理节点
     */
    private class ClearNode {

        /**
         * 下一节点
         */
        ClearNode next;

        /**
         * 清理中
         */
        volatile boolean clearing;

        /**
         * 当前节点前的所有节点清理干净后再执行
         */
        List<Runnable> afterClear = new ArrayList<>();

        /**
         * 正在清理中的节点,线程不安全
         */
        Collection<BranchNode<T>> clearingNodes;

    }

    /**
     * 当前清理中的节点
     */
    private ClearNode currentClearNode = new ClearNode();

    /**
     * 头节点
     */
    private volatile ClearNode headClearNode = currentClearNode;

    /**
     * 清理锁
     */
    private final Object clearLock = new Object();

    /**
     * 在清理完成后再执行
     *
     * @param runnable
     */
    public void runAfterClear(Runnable runnable) {

        boolean r = false;

        synchronized (clearLock) {

            if (headClearNode == currentClearNode) {
                //直接执行
                r = true;
            } else {
                currentClearNode.afterClear.add(runnable);
            }
        }

        if (r) {
            runnable.run();
        }

    }

    public void clear() {

        //清理分支集合
        Map<Object, BranchNode<T>> branchMap = this.branchMap;

        //新建
        this.branchMap = new HashMap<>();

        //正在清理中
        Collection<BranchNode<T>> branchNodes = branchMap.values();
        if (branchNodes.size() > 0) {


            ClearNode clearNode = new ClearNode();

            //标记为清理中
            clearNode.clearing = true;

            clearNode.clearingNodes = Collections.synchronizedSet(new HashSet<>(branchNodes));

            synchronized (clearLock) {

                //创建新的待清理节点
                this.currentClearNode.next = clearNode;

                this.currentClearNode = clearNode;

            }


            //遍历一遍再执行
            for (BranchNode<T> node : branchNodes) {
                node.flush(() -> {
                    //移除该元素
                    clearNode.clearingNodes.remove(node);
                    //移除完全
                    if (clearNode.clearingNodes.size() == 0) {

                        //cn 中的多个线程只有最后一个线程会执行到此处

                        List<ClearNode> clearNodes = new ArrayList<>();

                        synchronized (clearLock) {

                            clearNode.clearing = false;

                            //如果该节点是头节点
                            if (headClearNode == clearNode) {

                                ClearNode last = headClearNode;

                                while (true) {

                                    //如果正在清理中直接结束
                                    if (last.clearing) {
                                        break;
                                    }

                                    //搜集所有的任务
                                    clearNodes.add(last);

                                    if (last.next == null) {
                                        break;
                                    } else {
                                        last = last.next;
                                    }
                                }

                                //修改头节点为最后节点
                                headClearNode = last;

                            }
                        }

                        for (ClearNode cn : clearNodes) {
                            for (Runnable runnable : cn.afterClear) {
                                try {
                                    runnable.run();
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }


                });
            }

        }


        //父节点移除所有子分支
        parentBranch.setChildren(new ArrayList<>());

    }


    public class BranchResult {

        /**
         * 流程状态
         */

        private boolean newBranch;

        private BranchNode<T> branch;

        public BranchNode<T> getBranchNode() {
            return branch;
        }

        public boolean isNewBranch() {
            return newBranch;
        }

    }

    public Collection<BranchNode<T>> getAllBranch() {
        return branchMap.values();
    }

}
